﻿// vc.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//#include"stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")

using namespace std;

//DWORD WINAPI threadpro(LPVOID pParam) {
//	SOCKET hsock = (SOCKET)pParam;
//	char buffer[1024];
//	char sendBuffer[1024];
//	if (hsock != INVALID_SOCKET)
//		cout << "Start Receive " << endl;
//	while (1) {
//		int num = recv(hsock, buffer, 1024, 0);
//		if (num >= 0)
//			cout << "Receive from client" << buffer << endl;
//		if (!strcmp(buffer, "A")) {
//			memset(sendBuffer, 0, 1024);
//			strcpy_s(sendBuffer, "B");
//			int ires = send(hsock, sendBuffer, sizeof(sendBuffer), 0);
//			cout << "Send to client" << sendBuffer << endl;
//		}
//		else if (!strcmp(buffer, "C")) {
//			memset(sendBuffer, 0, 1024);
//			strcpy_s(sendBuffer, "D");
//			int ires = send(hsock, sendBuffer, sizeof(sendBuffer), 0);
//			cout << "Send to client" << sendBuffer << endl;
//		}
//		else if (!strcmp(buffer, "exit")) {
//			cout << "Client Close" << endl;
//			cout << "Server Process Close" << endl;
//			return 0;
//		}
//		else {
//			memset(sendBuffer, 0, 1024);
//			strcpy_s(sendBuffer, "ERR");
//			int ires = send(hsock, sendBuffer, sizeof(sendBuffer), 0);
//			cout << "Send to client" << sendBuffer << endl;
//			Sleep(2000);
//		}
//	}
//	return 0;
//}


// TCP与UDP区别
// UDP
// Server
// 创建SOCKET时指定SOCK_DGRAM
// 接收数据时，TCP使用recv UDP使用recvfrom
// bind()后直接收发数据 不需要listen、accept
// Client
// 创建SOCKET后直接收发数据 不需要connect
// 使用sendto发送数据
int main()
{
	WSADATA wsd;
	int x = WSAStartup(MAKEWORD(2, 2), &wsd); // 加载套接字库、协商套接字库的版本
	if (x != 0) {
		return -1;
	}
	cout << "wsd.wVersion: " << wsd.wVersion << endl;
	if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) {
		WSACleanup();
		return -1;
	}

	// socket
	SOCKET m_SockServer = socket(AF_INET, SOCK_STREAM, 0);
	// serveraddr
	sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	// TCP/IP协议族规定了所有在网络上传输的数据都应使用网络字节序进行编码
	// 大端序
	serveraddr.sin_port = htons(4600);
	//serveraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr.S_un.S_addr);
	//serveraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	// 调用成功返回0 
	int i = bind(m_SockServer, (sockaddr*)&serveraddr, sizeof(serveraddr));
	cout << "bind: " << i << endl;

	SOCKET m_Server[20];
	sockaddr_in serveraddrfrom;
	int len = sizeof(sockaddr);

	int iMaxConnect = 20;
	int iConnect = 0;
	char buf[] = "THIS IS SERVER...";
	char recvBuf[100];
	//char WarnBuf[] = "it is Over Max connect";

	listen(m_SockServer, 1/*等待连接队列的最大长度*/);

	while (1) {
		m_Server[iConnect] = accept(m_SockServer, (sockaddr*)&serveraddrfrom, &len);

		if (m_Server[iConnect] != INVALID_SOCKET) {
			int ires = send(m_Server[iConnect], buf, sizeof(buf), 0);
			cout << "send byte size : " << ires << endl;
			//WSAGetLastError();

			while (1) {
				int num = recv(m_Server[iConnect], recvBuf, sizeof(recvBuf), 0);
				if (num > 0) {
					if (!strcmp(recvBuf, "exit")) {
						closesocket(m_Server[iConnect]);
						WSACleanup();
						break;
					}
					if (!strcmp(recvBuf, "q")) {
						cout << "输入1退出，其他不理会: ";
						int select;
						cin >> select;
						if (select == 1) {
							closesocket(m_Server[iConnect]);
							WSACleanup();
							return 0;
						}
						else {
							send(m_Server[iConnect], "Server不理你...", 15, 0); // 一个中文占2个字符
						}
						continue;
					}
					cout << "reveive: " << recvBuf << endl;
					send(m_Server[iConnect], "hello", 5, 0);
					//send(m_Server[iConnect], buf, sizeof(buf), 0);
					cout << "reveive size: " << strlen(recvBuf) << endl;
				}
				else {
					Sleep(2000);
					cout << "休息两秒钟..." << endl;
				}
			}

			closesocket(m_Server[iConnect]);

			//iConnect++;
			//if (iConnect > iMaxConnect) {
			//	int ires = send(m_Server[iConnect], WarnBuf, sizeof(WarnBuf), 0);
			//}
			//else {
			//	HANDLE m_Handle;
			//	DWORD nThreadId = 0;
			//	m_Handle = (HANDLE)::CreateThread(NULL, 0,
			//		threadpro, (LPVOID)m_Server[--iConnect], 0, &nThreadId);
			//}
		}
	}
	system("pause");
	return 0;

	//unsigned long nCmd;
	//SOCKET clinetSock = socket(AF_INET, SOCK_STREAM, 0);
	//int nState = ioctlsocket(clinetSock, FIONBIO, &nCmd);
	//if(nState != 0) 
	//{
	//    cout << "设置套接字非阻塞模式失败" << endl;
	//}


}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
